using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using UtilZ.Dotnet.Ex.Base;
using UtilZ.Dotnet.Ex.DebugViews;
using UtilZ.Dotnet.Ex.ZLog;

namespace UtilZ.Dotnet.Ex.Model
{

#pragma warning disable 8500
    /// <summary>
    /// 值类型柔性数组,非线程安全类
    /// </summary>
    [DebuggerTypeProxy(typeof(StructSequenceDebugView<>))]
    [DebuggerDisplay("Length = {Length}")]
    unsafe public partial class ValueTypeFlexibleArray<T> : IEnumerable<T>, IDisposable
        where T : struct
    {
        private bool _disposed = false;
        private T _defaultValue = default(T);

        /// <summary>
        /// 构造函数初始化
        /// </summary>
        /// <param name="mode">工作模式</param>
        public ValueTypeFlexibleArray(FlexibleArrayMode mode)
        {
            this._mode = mode;
        }

        /// <summary>
        /// 引用数据源构造初始化实例,该实例不可扩展,也无需调用Dispose()方法释放资源
        /// </summary>
        /// <param name="buffer">原始数据buffer</param>
        /// <param name="length">数据长度</param>
        public ValueTypeFlexibleArray(T* buffer, int length)
            : this(FlexibleArrayMode.Referenced)
        {
            this._bufferPtr = buffer;
            this._length = length;
        }

        /// <summary>
        /// 引用数据源构造初始化实例,该实例不可扩展,也无需调用Dispose()方法释放资源
        /// </summary>
        /// <param name="buffer">原始数据buffer</param>
        public ValueTypeFlexibleArray(SpanZ<T> buffer)
            : this(FlexibleArrayMode.Referenced)
        {
            this._bufferPtr = buffer.DataPtr;
            this._length = buffer.Length;
        }

        /// <summary>
        /// 构造初始化实例,从buffer中拷贝一份数据到当前数组,不建议使用.可扩展.需调用Dispose()方法释放资源,否则将会内存泄露
        /// </summary>
        /// <param name="buffer">原始数据buffer</param>
        public ValueTypeFlexibleArray(Span<T> buffer)
            : this(FlexibleArrayMode.Independent)
        {
            this.ReallocArray(buffer.Length);
            buffer.CopyTo(new Span<T>(this._bufferPtr, buffer.Length));
            this._length = buffer.Length;
        }

        /// <summary>
        /// 根据初始化容量及数据长度构造初始化实例,可扩展.需调用Dispose()方法释放资源,否则将会内存泄露
        /// </summary>
        /// <param name="capcity">初始化容量</param>
        /// <param name="length">数据容量</param>
        public ValueTypeFlexibleArray(int capcity, int length)
            : this(FlexibleArrayMode.Independent)
        {
            if (length > capcity)
            {
                throw new ArgumentOutOfRangeException(nameof(length), $"数据长度\"{length}\"不能大小容量\"{capcity}\"");
            }

            this.ReallocArray(length);
            this._length = length;
        }

        /// <summary>
        /// 构造初始化实例,从buffer中拷贝一份数据到当前数组,不建议使用.可扩展.需调用Dispose()方法释放资源,否则将会内存泄露
        /// </summary>
        /// <param name="buffer">原始数据buffer</param>
        /// <param name="startIndex">起始索引位置</param>
        /// <param name="length">数据长度</param>
        public ValueTypeFlexibleArray(T[] buffer, int startIndex, int length)
            : this(FlexibleArrayMode.Independent)
        {
            if (buffer == null)
            {
                throw new ArgumentNullException(nameof(buffer));
            }

            if (startIndex < 0)
            {
                throw new ArgumentNullException(nameof(startIndex));
            }

            if (startIndex + length < 0 || startIndex + length > buffer.Length)
            {
                throw new ArgumentNullException(nameof(length));
            }

            if (startIndex + length > buffer.Length)
            {
                throw new ArgumentNullException(nameof(length));
            }

            this.ReallocArray(length);
            this._length = length;

            fixed (T* ptr = buffer)
            {
                NativeMemory.Copy(ptr + startIndex, this._bufferPtr, (nuint)(length * sizeof(T)));
            }
        }






        private readonly FlexibleArrayMode _mode;
        /// <summary>
        /// 获取当前实例模式
        /// </summary>
        public FlexibleArrayMode Mode
        {
            get { return this._mode; }
        }

        /// <summary>
        /// 判断当前数据源是否是当前数组维护的数据[true:当前数组维护的数据;false:引用的数据]
        /// </summary>
        /// <returns>true:当前数组维护的数据;false:引用的数据</returns>
        private bool IsIndependent()
        {
            return this._mode == FlexibleArrayMode.Independent;
        }

        /// <summary>
        /// 判断当前数据源是否是引用的数据[true:引用的数据;false:当前数组维护的数据]
        /// </summary>
        /// <returns>true:引用 的数据;false:当前数组维护的数据</returns>
        private bool IsReferenced()
        {
            return this._mode == FlexibleArrayMode.Referenced;
        }





        /// <summary>
        /// 数据buffer指针
        /// </summary>
        private T* _bufferPtr = null;
        private int _capcity = 0;


        private int _length = 0;
        /// <summary>
        /// 当前数组长度
        /// </summary>
        public int Length
        {
            get
            {
                return this._length;
            }
            set
            {
                if (value < 0 || value > this._capcity)
                {
                    throw new ArgumentOutOfRangeException($"数据长度{value}不能超出容量{this._capcity}.");
                }
                this._length = value;
            }
        }

        /// <summary>
        /// 获取或设置指定索引处的值
        /// </summary>
        /// <param name="index">索引</param>
        /// <returns></returns>
        public ref T this[int index]
        {
#if !NET4_0
            [MethodImpl(MethodImplOptions.AggressiveInlining)]
#endif
            get
            {
                if (index < 0 || index >= this._length)
                {
                    throw new IndexOutOfRangeException($"索引值\"{index}\"超出了数组范围,数据长度\"{this._length}\"");
                }

                return ref this._bufferPtr[index];
            }
            //[MethodImpl(MethodImplOptions.AggressiveInlining)]
            //set
            //{
            //    if (index < 0 || index >= this._length)
            //    {
            //        throw new IndexOutOfRangeException();
            //    }

            //    *(this.DataPtr + index) = value;
            //}
        }


        /// <summary>
        /// 获取第一个值,长度为0时抛出异常
        /// </summary>
        /// <returns></returns>
#if !NET4_0
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
#endif
        public ref T First()
        {
            if (this._length == 0)
            {
                throw new ArgumentException("没有数据");
            }
            else
            {
                return ref this._bufferPtr[0];
            }
        }

        /// <summary>
        /// 获取第一个值或长度为0时取类型T的默念值
        /// </summary>
        /// <returns></returns>
#if !NET4_0
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
#endif
        public ref T FirstOrDefault()
        {
            if (this._length == 0)
            {
                return ref this._defaultValue;
            }
            else
            {
                return ref this._bufferPtr[0];
            }
        }

        /// <summary>
        /// 获取最后一个值,长度为0时抛出异常
        /// </summary>
        /// <returns></returns>
#if !NET4_0
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
#endif
        public ref T Last()
        {
            if (this._length == 0)
            {
                throw new ArgumentException("没有数据");
            }
            else
            {
                return ref this._bufferPtr[this._length - 1];
            }
        }

        /// <summary>
        /// 获取最后一个值或长度为0时取类型T的默念值
        /// </summary>
        /// <returns>最后一个值或长度为0时取类型T的默念值</returns>
#if !NET4_0
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
#endif
        public ref T LastOrDefault()
        {
            if (this._length == 0)
            {
                return ref this._defaultValue;
            }
            else
            {
                return ref this._bufferPtr[this._length - 1];
            }
        }





        private int _count = 0;
        /// <summary>
        /// 获取或设置临时计数元素个数
        /// </summary>
        public int Count
        {
            get { return this._count; }
            set { this._count = value; }
        }

        /// <summary>
        /// 在现有Count值基础上加1
        /// </summary>
        /// <returns>旧值</returns>
        public int CountIncrement()
        {
            return Interlocked.Increment(ref this._count);
        }

        /// <summary>
        /// 在现有Count值基础上减1
        /// </summary>
        /// <returns>旧值</returns>
        public int CountDecrement()
        {
            return Interlocked.Decrement(ref this._count);
        }

        /// <summary>
        /// 在现有Count值基础上添加添加值
        /// </summary>
        /// <param name="value">添加值</param>
        /// <returns>旧值</returns>
        public int CountAdd(int value)
        {
            return Interlocked.Add(ref this._count, value);
        }

        /// <summary>
        /// 设置Count指定值
        /// </summary>
        /// <param name="value">目标值</param>
        /// <returns>旧值</returns>
        public int CountSet(int value)
        {
            return Interlocked.Exchange(ref this._count, value);
        }

        /// <summary>
        /// 获取或设置用户定义的数据
        /// </summary>
        public object Tag { get; set; }






        /// <summary>
        /// 检查容量是否足够,不够扩容,操作成功失败抛出异常
        /// </summary>
        /// <param name="length">需要的容量</param>
        public void Check(int length)
        {
            this.ReallocArray(length);
        }

        /// <summary>
        /// 检查容量是否足够,不够尝试扩容,操作成功返回true,失败返回false
        /// </summary>
        /// <param name="length">需要的容量</param>
        /// <returns>操作成功返回true,失败返回false</returns>
        public bool TryCheck(int length)
        {
            try
            {
                this.ReallocArray(length);
                return true;
            }
            catch (Exception ex)
            {
                ZLoger.Error(ex);
                return false;
            }
        }

        /// <summary>
        /// 检查容量是否足够,不够扩容.不调整或调整成功正常则设置数据长度为调整长度,操作成功失败抛出异常
        /// </summary>
        /// <param name="length">需要的元素个数</param>
        public void CheckSetLength(int length)
        {
            this.ReallocArray(length);
            this._length = length;
        }

        /// <summary>
        /// 检查容量是否足够,不够尝试扩容,操作成功返回true,失败返回false
        /// </summary>
        /// <param name="length">需要的元素个数</param>
        /// <returns>操作成功返回true,失败返回false</returns>
        public bool TryCheckSetLength(int length)
        {
            try
            {
                this.ReallocArray(length);
                this._length = length;
                return true;
            }
            catch (Exception ex)
            {
                ZLoger.Error(ex);
                return false;
            }
        }





        /// <summary>
        /// 获取当前数据长度的数据片
        /// </summary>
        /// <returns>数据片</returns>
        public Span<T> GetSpan()
        {
            return new Span<T>(this._bufferPtr, this._length);
        }

        /// <summary>
        /// 获取指定数据长度的数据片
        /// </summary>
        /// <param name="length">指定数据长度</param>
        /// <returns></returns>
        public Span<T> GetSpan(int length)
        {
            this.ReallocArray(length);
            return new Span<T>(this._bufferPtr, length);
        }

        /// <summary>
        /// 获取指定起始位置和数据长度的数据片
        /// </summary>
        /// <param name="startIndex">起始位置</param>
        /// <param name="count">指定数据长度</param>
        /// <returns></returns>
        public Span<T> GetSpan(int startIndex, int count)
        {
            if (startIndex < 0 || count < 0)
            {
                throw new ArgumentOutOfRangeException($"参数值无效,startIndex:{startIndex},count:{count}");
            }

            this.ReallocArray(startIndex + count);
            return new Span<T>(this._bufferPtr + startIndex, count);
        }

        /// <summary>
        /// 获取当前数据长度的数据片
        /// </summary>
        /// <returns>数据片</returns>
        public SpanZ<T> GetSpanZ()
        {
            return new SpanZ<T>(this._bufferPtr, this._length);
        }

        /// <summary>
        /// 获取指定数据长度的数据片
        /// </summary>
        /// <param name="length">指定数据长度</param>
        /// <returns></returns>
        public SpanZ<T> GetSpanZ(int length)
        {
            this.ReallocArray(length);
            return new SpanZ<T>(this._bufferPtr, length);
        }

        /// <summary>
        /// 获取指定起始位置和数据长度的数据片
        /// </summary>
        /// <param name="startIndex">起始位置</param>
        /// <param name="count">指定数据长度</param>
        /// <returns></returns>
        public SpanZ<T> GetSpanZ(int startIndex, int count)
        {
            if (startIndex < 0 || count < 0)
            {
                throw new ArgumentOutOfRangeException($"参数值无效,startIndex:{startIndex},count:{count}");
            }

            this.ReallocArray(startIndex + count);
            return new SpanZ<T>(this._bufferPtr + startIndex, count);
        }




        /// <summary>
        /// 创建一个数据流,外部需要释放流
        /// </summary>
        /// <param name="access">访问方式</param>
        /// <returns>数据流</returns>
        public Stream CreateStream(FileAccess access)
        {
            long byteCount = this._length * sizeof(T);
            return new UnmanagedMemoryStream((byte*)this._bufferPtr, byteCount, byteCount, access);
        }

        /// <summary>
        /// 创建一个数据流,外部需要释放流
        /// </summary>
        /// <param name="startIndex">起始位置</param>
        /// <param name="count">需要的数据元素个数</param>
        /// <param name="access">访问方式</param>
        /// <returns>数据流</returns>
        public Stream CreateStream(int startIndex, int count, FileAccess access)
        {
            if (startIndex < 0 || startIndex + count < 0)
            {
                throw new ArgumentOutOfRangeException($"参数值无效,startIndex:{startIndex},count:{count}");
            }

            if (startIndex + count > this._capcity)
            {
                this.ReallocArray(startIndex + count);
            }

            long byteCount = count * sizeof(T);
            return new UnmanagedMemoryStream((byte*)(this._bufferPtr + startIndex), byteCount, byteCount, access);
        }





        /// <summary>
        /// 用指定的值填充到当前对象数据指针指向的内容
        /// </summary>
        /// <param name="value">填充值</param>        
#if !NET4_0
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
#endif
        public void Fill(T value)
        {
            if (this._bufferPtr == null)
            {
                throw new InvalidOperationException($"当前数组没有数据");
            }

            UnmanagedMemoryHelper.Fill(this._bufferPtr, this._length, value);
        }

        /// <summary>
        /// 用指定的值填充到当前对象数据指针指向的内容
        /// </summary>
        /// <param name="startIndex">起始位置</param>
        /// <param name="count">填充个数</param>
        /// <param name="value">填充值</param>
#if !NET4_0
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
#endif
        public void Fill(int startIndex, int count, T value)
        {
            if (startIndex < 0 ||
                count < 0 ||
                startIndex + count > this._capcity)
            {
                throw new ArgumentOutOfRangeException($"参数值无效,startIndex:{startIndex},count:{count}");
            }

            UnmanagedMemoryHelper.Fill(this._bufferPtr + startIndex, count, value);
        }



        /// <summary>
        /// 将数据拷贝到列表中
        /// </summary>
#if !NET4_0
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
#endif
        public List<T> ToList()
        {
            if (this._length <= 0)
            {
                return new List<T>();
            }

            T* ptr = this._bufferPtr;
            var destination = new List<T>(this._length);
            for (int i = 0; i < this._length; i++)
            {
                destination.Add(*ptr++);
            }

            return destination;
        }




        /// <summary>
        /// 分片返回一个固定的柔性数组
        /// </summary>
        /// <param name="start">The index at which to begin this slice.</param>
        /// <exception cref="ArgumentOutOfRangeException">
        /// Thrown when the specified <paramref name="start"/> index is not in range (&lt;0 or &gt;Length).
        /// </exception>
#if !NET4_0
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
#endif
        public ValueTypeFlexibleArray<T> Slice(int start)
        {
            if (start < 0 || start > this._length)
            {
                throw new ArgumentOutOfRangeException(nameof(start), $"start:{start},Length:{this._length}");
            }

            return new ValueTypeFlexibleArray<T>(this._bufferPtr + start, this._length - start);
        }

        /// <summary>
        /// 分片返回一个固定的柔性数组
        /// </summary>
        /// <param name="start">The index at which to begin this slice.</param>
        /// <param name="length">The desired length for the slice (exclusive).</param>
        /// <exception cref="ArgumentOutOfRangeException">
        /// Thrown when the specified <paramref name="start"/> or end index is not in range (&lt;0 or &gt;Length).
        /// </exception>
#if !NET4_0
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
#endif
        public ValueTypeFlexibleArray<T> Slice(int start, int length)
        {
            if (start < 0 || start > this._length)
            {
                throw new ArgumentOutOfRangeException(nameof(start), $"start:{start},length:{length},Length:{this._length}");
            }

            if (start + length > this._length)
            {
                throw new ArgumentOutOfRangeException(nameof(length), $"start:{start},length:{length},Length:{this._length}");
            }

            return new ValueTypeFlexibleArray<T>(this._bufferPtr + start, length);
        }



        /// <summary>
        /// 引用数据
        /// </summary>
        /// <param name="dataPtr">被引用数据的数据指针</param>
        /// <param name="length">被引用数据的数据长度</param>
        public void Reference(T* dataPtr, int length)
        {
            if (length < 0)
            {
                throw new ArgumentOutOfRangeException($"长度值\"{length}\"无效,超出范围,不能小于0");
            }

            if (this.IsIndependent())
            {
                throw new InvalidOperationException($"当前数组对象模式为内存独立模式,不支持引用其它对象的数据内存.");
            }

            this._bufferPtr = dataPtr;
            this._length = length;
        }

        /// <summary>
        /// 引用数据
        /// </summary>
        /// <param name="data">被引用数据的数据</param>
        public void Reference(SpanZ<T> data)
        {
            if (data.Length <= 0)
            {
                return;
            }

            if (this.IsIndependent())
            {
                throw new InvalidOperationException($"当前数组对象模式为内存独立模式,不支持引用其它对象的数据内存.");
            }

            this._bufferPtr = data.DataPtr;
            this._length = data.Length;
        }

        /// <summary>
        /// 引用数据
        /// </summary>
        /// <param name="arr">被引用数据的数组</param>
        public void Reference(ValueTypeFlexibleArray<T> arr)
        {
            if (arr == null)
            {
                return;
            }

            if (this.IsIndependent())
            {
                throw new InvalidOperationException($"当前数组对象模式为内存独立模式,不支持引用其它对象的数据内存.");
            }

            this._bufferPtr = arr._bufferPtr;
            this._length = arr._length;
            this._capcity = arr._capcity;
        }

        /// <summary>
        /// 引用数据
        /// </summary>
        /// <param name="arr">被引用数据的数组</param>
        /// <param name="startIndex">被引用数据的数据起始偏移位置</param>
        /// <param name="length">被引用数据的数据长度</param>
        public void Reference(ValueTypeFlexibleArray<T> arr, int startIndex, int length)
        {
            if (arr == null)
            {
                return;
            }

            if (startIndex < 0)
            {
                throw new ArgumentOutOfRangeException($"数据起始偏移位置\"{startIndex}\"无效,超出范围,不能小于0");
            }

            if (startIndex + length < 0)
            {
                throw new ArgumentOutOfRangeException($"长度值\"{startIndex + length}\"无效,超出范围,不能小于0");
            }

            if (startIndex + length > arr._length)
            {
                throw new ArgumentOutOfRangeException($"起始索引{startIndex}加长度值\"{startIndex + length}\"无效,超出范围");
            }

            if (this.IsIndependent())
            {
                throw new InvalidOperationException($"当前数组对象模式为内存独立模式,不支持引用其它对象的数据内存.");
            }

            this._bufferPtr = arr._bufferPtr + startIndex;
            this._length = length;
            this._capcity = length;
        }




        /// <summary>
        /// 重写ToString
        /// </summary>
        /// <returns>String</returns>
        public override string ToString()
        {
            var sb = new StringBuilder();
            for (int i = 0; i < this._length; i++)
            {
                if (sb.Length > 0)
                {
                    sb.Append(',');
                }
                sb.Append(this._bufferPtr[i]);
            }
            return sb.ToString();
        }

        /// <summary>
        /// 重写ToString
        /// </summary>
        /// <returns>String</returns>
        public string ToString(char separator)
        {
            var sb = new StringBuilder();
            for (int i = 0; i < this._length; i++)
            {
                if (sb.Length > 0)
                {
                    sb.Append(separator);
                }
                sb.Append(this._bufferPtr[i]);
            }
            return sb.ToString();
        }

        /// <summary>
        /// 重写ToString
        /// </summary>
        /// <returns>String</returns>
        public string ToString(string separator)
        {
            var sb = new StringBuilder();
            for (int i = 0; i < this._length; i++)
            {
                if (sb.Length > 0)
                {
                    sb.Append(separator);
                }
                sb.Append(this._bufferPtr[i]);
            }
            return sb.ToString();
        }



        #region IEnumerator

        /// <summary>
        /// IEnumerable
        /// </summary>
        /// <returns></returns>
        public IEnumerator<T> GetEnumerator()
        {
            return new ValueTypeFlexibleArrayEnumerator(this);
        }

        IEnumerator IEnumerable.GetEnumerator()
        {
            return this.GetEnumerator();
        }

        internal class ValueTypeFlexibleArrayEnumerator : IEnumerator<T>
        {
            private readonly ValueTypeFlexibleArray<T> _arr;
            private int _index = -1;
            public ValueTypeFlexibleArrayEnumerator(ValueTypeFlexibleArray<T> arr)
            {
                this._arr = arr;
            }

            public T Current
            {
                get
                {
                    return this._arr[this._index];
                }
            }

            object System.Collections.IEnumerator.Current
            {
                get
                {
                    return this.Current;
                }
            }


            public void Dispose()
            {

            }

            public bool MoveNext()
            {
                this._index++;
                if (this._index < this._arr._length)
                {
                    return true;
                }
                else
                {
                    return false;
                }
            }

            public void Reset()
            {
                this._index = -1;
            }
        }
        #endregion

    }

    /// <summary>
    /// 型柔性数组工作模式
    /// </summary>
    public enum FlexibleArrayMode
    {
        /// <summary>
        /// 引用内存模式,无需调用Dispose方法释放内存,调用也不执行操作
        /// </summary>
        Referenced,

        /// <summary>
        /// 内存独立模式,需要调用Dispose方法释放内存
        /// </summary>
        Independent
    }

}
